

'use strict'

var Promise=require('bluebird')
var request=Promise.promisify(require('request'))
var util=require('./util')
var fs=require('fs')
var _=require('lodash')

var prefix='https://api.weixin.qq.com/cgi-bin/'
var api={
    accessToken:prefix+'token?grant_type=client_credential',
    temporay:{
        upload:prefix+'media/upload?',
        fetch:prefix+'media/get?'
    },
    permanent:{
        upload:prefix+'material/add_material?',
        fetch:prefix+'material/get_material?',
        uploadNews:prefix+'material/add_news?',
        uploadNewsPic:prefix+'media/uploadimg?',
        del:prefix+'material/del_material?',
        update:prefix+'material/update_news?',
        count:prefix+'material/get_materialcount?',
        batch:prefix+'material/batchget_material?',
    },
    tags:{
        create:prefix+'tags/create?',//创建分组
        fetch:prefix+'tags/get?',//查询分组
        check:prefix+'tags/getidlist?',
        update:prefix+'tags/update?',
        batchupdate:prefix+'tags/members/batchtagging?',
        batchdelete:prefix+'tags/delete?',
    },
    user:{
        remark:prefix+'user/info/updateremark?',
        fetch:prefix+'user/info?',
        batchFetch:prefix+'user/info/batchget?',
        list:prefix+'user/get?',
        
    },
    mass:{
        group:prefix+'message/mass/sendall?',
        openId:prefix+'message/mass/send?',
        del:prefix+'message/mass/delete?',
        preview:prefix+'message/mass/preview?',
        check:prefix+'message/mass/get?',
    },
    menu:{
        create:prefix+'menu/create?',
        get:prefix+'menu/get?',
        del:prefix+'menu/delete?',
        current:prefix+'get_current_selfmenu_info?',
    },
    ticket:{
        get:prefix+'ticket/getticket?'
    }
    
}

   function Wechat(opts){
    var that=this
    this.appID=opts.appID
    this.appSecret=opts.appSecret
    this.access_token=''
    this.expires_in=''
    this.getAccessToken=opts.getAccessToken
    this.saveAccessToken=opts.saveAccessToken
    this.getTicket=opts.getTicket
    this.saveTicket=opts.saveTicket


    this.fetchAccessToken()
}

Wechat.prototype.fetchAccessToken=function(data){
     
    var that =this

    if (this.access_token&&this.expires_in) {
        if (this.isValidAccessToken(this)) {
            return Promise.resolve(this)
        }
    }
     return  this.getAccessToken().then(function(data){
        try {
            data=JSON.parse(data.toString()) 
        } catch (error) {
            return that.updateAccessToken()
        }
        if (that.isValidAccessToken(data)) {
            return  Promise.resolve(data)
        } else {
            return that.updateAccessToken()
        }
    }).then(function(data){
        that.access_token=data.access_token
        that.expires_in=data.expires_in

        that.saveAccessToken(data)

        return Promise.resolve(data)
    })
}

Wechat.prototype.fetchTicket=function(access_token){
     
    var that =this

     return  this.getTicket().then(function(data){
        try {
            data=JSON.parse(data.toString()) 
        } catch (error) {
            return that.updateTicket(access_token)
        }
        if (that.isValidTicket(data)) {
            return  Promise.resolve(data)
        } else {
            return that.updateTicket(access_token)
        }
    }).then(function(data){

        that.saveTicket(data)

        return Promise.resolve(data)
    })
}

Wechat.prototype.isValidAccessToken=function(data){
    if (!data || !data.access_token || !data.expires_in ) {
        return false
    }
    var access_token=data.access_token
    var expires_in=data.expires_in
    var now=(new Date().getTime())

    if (now<expires_in) {
        return true
    } else {
        return false
    }
}

Wechat.prototype.isValidTicket=function(data){
    if (!data || !data.ticket || !data.expires_in ) {
        return false
    }
    var ticket=data.ticket
    var expires_in=data.expires_in
    var now=(new Date().getTime())

    if (ticket&&now<expires_in) {
        return true
    } else {
        return false
    }
}


Wechat.prototype.updateAccessToken=function(){
    var appID=this.appID
    var appSecret=this.appSecret
    var url=api.accessToken+'&appid='+appID+'&secret='+appSecret

    return new Promise(function(resolve,reject){
        request({url:url,json:true}).then(function(response){
            var data=response.body
            var now=(new Date().getTime())
            var expires_in=now+(data.expires_in-20)*1000
    
            data.expires_in=expires_in 
            
            resolve(data)
        })
    })

}

Wechat.prototype.updateTicket=function(access_token){
    var url=api.ticket.get+'&access_token='+access_token+'&type=jsapi'

    return new Promise(function(resolve,reject){
        request({url:url,json:true}).then(function(response){
            var data=response.body
            var now=(new Date().getTime())
            var expires_in=now+(data.expires_in-20)*1000
    
            data.expires_in=expires_in 
            
            resolve(data)
        })
    })

}


Wechat.prototype.uploadMaterial=function(type,material,permanent){
    var that=this
    var form={}
    var uploadUrl=api.temporay.upload
    
    if (permanent) {
        uploadUrl=api.permanent.upload
        _.extend(form,permanent)
    }
    if (type==='pic') {
        uploadUrl=api.permanent.uploadNewsPic
    }
    if (type==='news') {
        uploadUrl=api.permanent.uploadNews
        form=material
    }else{
        form.media=fs.createReadStream(material)
    }

    return new Promise(function(resolve,reject){
        that
           .fetchAccessToken()
           .then(function(data){
               
               var url=uploadUrl+'&access_token='+data.access_token

               if (!permanent) {
                   url+='&type='+type 
               }else{
                   form.access_token=data.access_token
               }

               var options={
                   method:'POST',
                   url:url,
                   headers:"{Content-Type: text/plain}",
                   json:true,
               }

               if (type==='news') {
                   options.body=form
               }else{
                   options.formData=form
               }
               request(options).then(function(response){
                    var _data=response.body
                    console.log('_data_',response.body)
                    if (_data) {
                        resolve(_data)
                    }else{
                        throw new Error('Upload material fails')
                    }
                    
                }).catch(function(err){
                    reject(err)
                })
           })
    })

}

Wechat.prototype.fetchMaterial=function(mediaId,type,permanent){
    var that=this
    var fetchUrl=api.temporay.fetch
    
    if (permanent) {
        fetchUrl=api.permanent.fetch
    }

    return new Promise(function(resolve,reject){
        that
           .fetchAccessToken()
           .then(function(data){
               
               var url=fetchUrl+'&access_token='+data.access_token

               var  form={}

               var options={
                    method:'POST',
                    url:url,
                    headers:"{Content-Type: text/plain}",
                    json:true,
                }
               if (permanent) {
                    form.media_id=mediaId
                    form.access_token=data.access_token
                    options.body=form
                }else{
                    if (type==='video') {
                        url=url.replace('https://','http://')
                    }
                    url+='&media_id'+mediaId
                }

                console.log('options',options)

                if (type==='news' || type==='video') {
                    request(options).then(function(response){
                        var _data=response.body
                        console.log('url_data',_data)
                        if (_data) {
                            resolve(_data)
                        }else{
                            throw new Error('fetch material fails')
                        }
                        
                    }).catch(function(err){
                        reject(err)
                    })                    
                } else {
                    resolve(url)
                }

           })
    })

}

Wechat.prototype.deleteMaterial=function(mediaId){
    var that=this
    var form={
        media_id:mediaId
    }

    return new Promise(function(resolve,reject){
        that
           .fetchAccessToken()
           .then(function(data){
               
               var url=api.permanent.del+'&access_token='+data.access_token+'&media_id='+mediaId


               var options={
                    method:'POST',
                    url:url,
                    headers:"{Content-Type: text/plain}",
                    json:true,
                    body:form
                }
               request(options).then(function(response){
                    var _data=response.body
                    console.log('_data',response.body)
                    if (_data) {
                        resolve(_data)
                    }else{
                        throw new Error('delete material fails')
                    }
                    
                }).catch(function(err){
                    reject(err)
                })
           })
    })

}

Wechat.prototype.updateMaterial=function(mediaId,news){
    var that=this
    var form={
        media_id:mediaId
    }

    _.extend(form,news)

    return new Promise(function(resolve,reject){
        that
           .fetchAccessToken()
           .then(function(data){
               
               var url=api.permanent.update+'&access_token='+data.access_token+'&media_id='+mediaId


               var options={
                    method:'POST',
                    url:url,
                    headers:"{Content-Type: text/plain}",
                    json:true,
                    body:form
                }
               request(options).then(function(response){
                    var _data=response.body
                    console.log('_data',response.body)
                    if (_data) {
                        resolve(_data)
                    }else{
                        throw new Error('update material fails')
                    }
                    
                }).catch(function(err){
                    reject(err)
                })
           })
    })

}


Wechat.prototype.countMaterial=function(){
    var that=this

    return new Promise(function(resolve,reject){
        that
           .fetchAccessToken()
           .then(function(data){
               
               var url=api.permanent.count+'&access_token='+data.access_token


               var options={
                    method:'GET',
                    url:url,
                    headers:"{Content-Type: text/plain}",
                    json:true,
                }
               request(options).then(function(response){
                    var _data=response.body
                    console.log('_data',response.body)
                    if (_data) {
                        resolve(_data)
                    }else{
                        throw new Error('count material fails')
                    }
                    
                }).catch(function(err){
                    reject(err)
                })
           })
    })

}


Wechat.prototype.batchMaterial=function(opt){
    var that=this
    opt.type=opt.type || 'image'
    opt.offset=opt.type || 0
    opt.count=opt.count || 1

    return new Promise(function(resolve,reject){
        that
           .fetchAccessToken()
           .then(function(data){
               
               var url=api.permanent.batch+'&access_token='+data.access_token


               var options={
                    method:'POST',
                    url:url,
                    headers:"{Content-Type: text/plain}",
                    json:true,
                    body:opt
                }
               request(options).then(function(response){
                    var _data=response.body
                    console.log('_data',response.body)
                    if (_data) {
                        resolve(_data)
                    }else{
                        throw new Error('count material fails')
                    }
                    
                }).catch(function(err){
                    reject(err)
                })
           })
    })

}

Wechat.prototype.createTag=function(name){
    var that=this

    return new Promise(function(resolve,reject){
        that
           .fetchAccessToken()
           .then(function(data){
               
               var url=api.tags.create+'&access_token='+data.access_token
               
               var form={
                    tag:{
                        name:name  
                    }
               }

               var options={
                    method:'POST',
                    url:url,
                    headers:"{Content-Type: text/plain}",
                    json:true,
                    body:form
                }
               request(options).then(function(response){
                    var _data=response.body
                    console.log('_data',response.body)
                    if (_data) {
                        resolve(_data)
                    }else{
                        throw new Error('count material fails')
                    }
                    
                }).catch(function(err){
                    reject(err)
                })
           })
    })

}


Wechat.prototype.fetchTag=function(){
    var that=this

    return new Promise(function(resolve,reject){
        that
           .fetchAccessToken()
           .then(function(data){
               
               var url=api.tags.fetch+'&access_token='+data.access_token
               

               var options={
                    url:url,
                    headers:"{Content-Type: text/plain}",
                    json:true,
                }
               request(options).then(function(response){
                    var _data=response.body
                    console.log('_data',response.body)
                    if (_data) {
                        resolve(_data)
                    }else{
                        throw new Error('count material fails')
                    }
                    
                }).catch(function(err){
                    reject(err)
                })
           })
    })

}


Wechat.prototype.checkTag=function(openid){
    var that=this

    return new Promise(function(resolve,reject){
        that
           .fetchAccessToken()
           .then(function(data){
               
               var url=api.tags.check+'&access_token='+data.access_token
               
               var form={
                   openid:openid
               }

               var options={
                    method:'POST',
                    url:url,
                    headers:"{Content-Type: text/plain}",
                    json:true,
                    body:form
                }
               request(options).then(function(response){
                    var _data=response.body
                    console.log('_data',response.body)
                    if (_data) {
                        resolve(_data)
                    }else{
                        throw new Error('count material fails')
                    }
                    
                }).catch(function(err){
                    reject(err)
                })
           })
    })

}

Wechat.prototype.batchupdate=function(openid,tagid){
    var that=this

    return new Promise(function(resolve,reject){
        that
           .fetchAccessToken()
           .then(function(data){
               
               var url=api.tags.batchupdate+'&access_token='+data.access_token
               
               var form={
                openid_list:[openid],
                tagid:tagid
               }

               var options={
                    method:'POST',
                    url:url,
                    headers:"{Content-Type: text/plain}",
                    json:true,
                    body:form
                }
               request(options).then(function(response){
                    var _data=response.body
                    console.log('_data',response.body)
                    if (_data) {
                        resolve(_data)
                    }else{
                        throw new Error('batchupdate material fails')
                    }
                    
                }).catch(function(err){
                    reject(err)
                })
           })
    })

}


Wechat.prototype.updatetag=function(id,name){
    var that=this

    return new Promise(function(resolve,reject){
        that
           .fetchAccessToken()
           .then(function(data){
               
               var url=api.tags.update+'&access_token='+data.access_token
               
               var form={
                  tag:{
                    id:id,
                    name:name
                  }
               }

               var options={
                    method:'POST',
                    url:url,
                    headers:"{Content-Type: text/plain}",
                    json:true,
                    body:form
                }
               request(options).then(function(response){
                    var _data=response.body
                    // console.log('_data',response.body)
                    if (_data) {
                        resolve(_data)
                    }else{
                        throw new Error('update material fails')
                    }
                    
                }).catch(function(err){
                    reject(err)
                })
           })
    })

}

Wechat.prototype.deletetag=function(id){
    var that=this

    return new Promise(function(resolve,reject){
        that
           .fetchAccessToken()
           .then(function(data){
               
               var url=api.tags.batchdelete+'&access_token='+data.access_token
               
               var form={
                  tag:{
                    id:id,
                  }
               }

               var options={
                    method:'POST',
                    url:url,
                    headers:"{Content-Type: text/plain}",
                    json:true,
                    body:form
                }
               request(options).then(function(response){
                    var _data=response.body
                    // console.log('_data',response.body)
                    if (_data) {
                        resolve(_data)
                    }else{
                        throw new Error('batchdelete material fails')
                    }
                    
                }).catch(function(err){
                    reject(err)
                })
           })
    })

}


Wechat.prototype.remarkUser=function(openId,remark){
    var that=this

    return new Promise(function(resolve,reject){
        that
           .fetchAccessToken()
           .then(function(data){
               
               var url=api.user.remark+'&access_token='+data.access_token
               
               var form={
                  openid:openId,
                  remark:remark
               }

               var options={
                    method:'POST',
                    url:url,
                    headers:"{Content-Type: text/plain}",
                    json:true,
                    body:form
                }
               request(options).then(function(response){
                    var _data=response.body
                    // console.log('_data',response.body)
                    if (_data) {
                        resolve(_data)
                    }else{
                        throw new Error('remark material fails')
                    }
                    
                }).catch(function(err){
                    reject(err)
                })
           })
    })

}


Wechat.prototype.fetchUsers=function(openIds,lang){
    var that=this
    lang=lang || 'zh_CN'
    return new Promise(function(resolve,reject){
        that
           .fetchAccessToken()
           .then(function(data){
                var url;
                var options={
                    headers:"{Content-Type: text/plain}",
                    json:true,
                }
                if (_.isArray(openIds)) {
                    options.url=api.user.batchFetch+'&access_token='+data.access_token
                    options.body={
                        user_list:openIds
                     }
                     options.method='POST'
                } else {
                    options.url=api.user.fetch+'&access_token='+data.access_token+'&openid='+openIds+'&lang='+lang
                }
          
               request(options).then(function(response){
                    var _data=response.body
                    // console.log('_data',response.body)
                    if (_data) {
                        resolve(_data)
                    }else{
                        throw new Error('batch fetch material fails')
                    }
                    
                }).catch(function(err){
                    reject(err)
                })
           })
    })

}


Wechat.prototype.listkUsers=function(openId){
    var that=this

    return new Promise(function(resolve,reject){
        that
           .fetchAccessToken()
           .then(function(data){
               
               var url=api.user.list+'&access_token='+data.access_token
               if (openId) {
                   url+='&next_openid='+openId
               }
               var options={
                    url:url,
                    headers:"{Content-Type: text/plain}",
                    json:true,
                }
               request(options).then(function(response){
                    var _data=response.body
                    // console.log('_data',response.body)
                    if (_data) {
                        resolve(_data)
                    }else{
                        throw new Error('remark material fails')
                    }
                    
                }).catch(function(err){
                    reject(err)
                })
           })
    })

}

Wechat.prototype.sendByGroup=function(type,message,groupId){
    var that=this

    var msg={
        filter:{},
        msgtype:type
    }

    msg[type]=message

    if (!groupId) {
        msg.filter.is_to_all=true
    }else{
        msg.filter={
            is_to_all:false,
            tag_id:groupId
        }
    }

    return new Promise(function(resolve,reject){
        that
           .fetchAccessToken()
           .then(function(data){
               
               var url=api.mass.group+'&access_token='+data.access_token

               var options={
                    method:'POST',
                    url:url,
                    headers:"{Content-Type: text/plain}",
                    json:true,
                    body:msg
                }
               request(options).then(function(response){
                    var _data=response.body
                    // console.log('_data',response.body)
                    if (_data) {
                        resolve(_data)
                    }else{
                        throw new Error('mass  group  fails')
                    }
                    
                }).catch(function(err){
                    reject(err)
                })
           })
    })

}

Wechat.prototype.sendByOpenId=function(type,message,openIds){
    var that=this

    var msg={
        msgtype:type,
        touser:openIds
    }

    msg[type]=message

    return new Promise(function(resolve,reject){
        that
           .fetchAccessToken()
           .then(function(data){
               
               var url=api.mass.openId+'&access_token='+data.access_token

               var options={
                    method:'POST',
                    url:url,
                    headers:"{Content-Type: text/plain}",
                    json:true,
                    body:msg
                }
               request(options).then(function(response){
                    var _data=response.body
                    // console.log('_data',response.body)
                    if (_data) {
                        resolve(_data)
                    }else{
                        throw new Error('mass  openId  fails')
                    }
                    
                }).catch(function(err){
                    reject(err)
                })
           })
    })

}

Wechat.prototype.deleteMass=function(msgId){
    var that=this

    return new Promise(function(resolve,reject){
        that
           .fetchAccessToken()
           .then(function(data){
               
               var url=api.mass.del+'&access_token='+data.access_token
               var form={
                   msg_id:msgId
               }
               var options={
                    method:'POST',
                    url:url,
                    headers:"{Content-Type: text/plain}",
                    json:true,
                    body:form
                }
               request(options).then(function(response){
                    var _data=response.body
                    // console.log('_data',response.body)
                    if (_data) {
                        resolve(_data)
                    }else{
                        throw new Error('mass  delete  fails')
                    }
                    
                }).catch(function(err){
                    reject(err)
                })
           })
    })

}

Wechat.prototype.previewMass=function(type,message,openId){
    var that=this

    var msg={
        msgtype:type,
        touser:openId
    }

    msg[type]=message

    return new Promise(function(resolve,reject){
        that
           .fetchAccessToken()
           .then(function(data){
               
               var url=api.mass.preview+'&access_token='+data.access_token
               var options={
                    method:'POST',
                    url:url,
                    headers:"{Content-Type: text/plain}",
                    json:true,
                    body:msg
                }
               request(options).then(function(response){
                    var _data=response.body
                    // console.log('_data',response.body)
                    if (_data) {
                        resolve(_data)
                    }else{
                        throw new Error('mass  preview  fails')
                    }
                    
                }).catch(function(err){
                    reject(err)
                })
           })
    })

}

Wechat.prototype.checkMass=function(msgId){
    var that=this

    return new Promise(function(resolve,reject){
        that
           .fetchAccessToken()
           .then(function(data){
               
               var url=api.mass.check+'&access_token='+data.access_token
               var form={
                    msg_id:msgId
                }
               var options={
                    method:'POST',
                    url:url,
                    headers:"{Content-Type: text/plain}",
                    json:true,
                    body:form
                }
               request(options).then(function(response){
                    var _data=response.body
                    // console.log('_data',response.body)
                    if (_data) {
                        resolve(_data)
                    }else{
                        throw new Error('mass  preview  fails')
                    }
                    
                }).catch(function(err){
                    reject(err)
                })
           })
    })

}

Wechat.prototype.createMenu=function(menu){
    var that=this

    return new Promise(function(resolve,reject){
        that
           .fetchAccessToken()
           .then(function(data){
               
               var url=api.menu.create+'&access_token='+data.access_token

               var options={
                    method:'POST',
                    url:url,
                    headers:"{Content-Type: text/plain}",
                    json:true,
                    body:menu
                }
               request(options).then(function(response){
                    var _data=response.body
                    // console.log('_data',response.body)
                    if (_data) {
                        resolve(_data)
                    }else{
                        throw new Error('create  menu  fails')
                    }
                    
                }).catch(function(err){
                    reject(err)
                })
           })
    })

}

Wechat.prototype.getMenu=function(){
    var that=this

    return new Promise(function(resolve,reject){
        that
           .fetchAccessToken()
           .then(function(data){
               
               var url=api.menu.get+'&access_token='+data.access_token

               var options={
                    url:url,
                    headers:"{Content-Type: text/plain}",
                    json:true,
                }
               request(options).then(function(response){
                    var _data=response.body
                    // console.log('_data',response.body)
                    if (_data) {
                        resolve(_data)
                    }else{
                        throw new Error('get  menu  fails')
                    }
                    
                }).catch(function(err){
                    reject(err)
                })
           })
    })

}


Wechat.prototype.deleteMenu=function(){
    var that=this

    return new Promise(function(resolve,reject){
        that
           .fetchAccessToken()
           .then(function(data){
               
               var url=api.menu.del+'&access_token='+data.access_token

               var options={
                    url:url,
                    headers:"{Content-Type: text/plain}",
                    json:true,
                }
                console.log('deleteMenu.options',options)
               request(options).then(function(response){
                    var _data=response.body
                    // console.log('_data',response.body)
                    if (_data) {
                        resolve(_data)
                    }else{
                        throw new Error('delete  menu  fails')
                    }
                    
                }).catch(function(err){
                    reject(err)
                })
           })
    })

}

Wechat.prototype.getCurrentMenu=function(){
    var that=this

    return new Promise(function(resolve,reject){
        that
           .fetchAccessToken()
           .then(function(data){
               
               var url=api.menu.current+'&access_token='+data.access_token

               var options={
                    url:url,
                    headers:"{Content-Type: text/plain}",
                    json:true,
                }
               request(options).then(function(response){
                    var _data=response.body
                    // console.log('_data',response.body)
                    if (_data) {
                        resolve(_data)
                    }else{
                        throw new Error('current  menu  fails')
                    }
                    
                }).catch(function(err){
                    reject(err)
                })
           })
    })

}

Wechat.prototype.reply=function(){
    var content=this.body
    var message=this.weixin
    var xml=util.tpl(content,message)
    this.status=200
    this.type='application/xml'
    this.body=xml

}


module.exports=Wechat